﻿'
' Will Strohl (wills@strohlsitedesign.com)
' http://www.willstrohl.com
'
'Copyright (c) 2009, Will Strohl
'All rights reserved.
'
'Redistribution and use in source and binary forms, with or without modification, are 
'permitted provided that the following conditions are met:
'
'Redistributions of source code must retain the above copyright notice, this list of 
'conditions and the following disclaimer.
'
'Redistributions in binary form must reproduce the above copyright notice, this list 
'of conditions and the following disclaimer in the documentation and/or other 
'materials provided with the distribution.
'
'Neither the name of StrohlSiteDesign.com nor the names of its contributors may be 
'used to endorse or promote products derived from this software without specific prior 
'written permission.
'
'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
'EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
'OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
'SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
'INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
'TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
'BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
'CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
'ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
'DAMAGE.
'

Imports DnnModules = DotNetNuke.Entities.Modules
Imports System.Collections.Generic
Imports System.IO
Imports System.Net
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Web.UI.WebControls

Namespace WillStrohl.Modules.FeedHandler

    ''' <summary>
    ''' FeedHandlerController - this class handles all of the high-level BLL
    ''' </summary>
    ''' <remarks></remarks>
    ''' <history>
    ''' </history>
    Public NotInheritable Class FeedHandlerController

#Region " Constants "

        Public Const ARRAY_DELIMITER As String = "?"
        Public Const FEEDHANDLER_URL As String = "http://{0}/DesktopModules/{1}/Feed.ashx?fid={2}&amp;mid={3}&amp;ic={4}"
        Public Const PARAM_MODULE_ID As String = "mid"
        Public Const PARAM_FEED_ID As String = "fid"
        Public Const PARAM_ITEM_COUNT As String = "ic"
        Public Const CONTENT_TYPE_XML As String = "text/xml"
        Public Const XML_HEADER As String = "<?xml version=""1.0"" encoding=""UTF-8"" ?>"
        Public Const XML_ELEMENT As String = "<{0}><![CDATA[{1}]]></{0}>"
        Public Const XML_OPEN As String = "<{0}>"
        Public Const XML_CLOSE As String = "</{0}>"
        Public Const CONTENT_ENCODING As String = "UTF-8"

#End Region

#Region " DAL Methods "

        Public Shared Function GetFeed(ByVal FeedId As Integer) As FeedInfo
            Dim coll As New FeedInfoCollection
            coll.Fill(DataProvider.Instance().GetFeed(FeedId))
            If coll.Count > 0 Then
                Return coll(0)
            Else
                Return Nothing
            End If
        End Function

        Public Shared Function GetFeeds(ByVal ModuleId As Integer) As FeedInfoCollection
            Dim coll As New FeedInfoCollection
            coll.Fill(DataProvider.Instance().GetFeeds(ModuleId))
            If coll.Count > 0 Then
                Return coll
            Else
                Return Nothing
            End If
        End Function

        Public Shared Function AddFeed(ByVal FeedName As String, ByVal ModuleId As Integer, ByVal FeedModuleId As Integer, ByVal FeedImportUrl As String, ByVal FeedUrl As String) As Integer
            Return DataProvider.Instance().AddFeed(ModuleId, FeedName, FeedModuleId, FeedImportUrl, FeedUrl)
        End Function

        Public Shared Sub UpdateFeed(ByVal FeedId As Integer, ByVal FeedName As String, ByVal ModuleId As Integer, ByVal FeedModuleId As Integer, ByVal FeedImportUrl As String, ByVal FeedUrl As String)
            DataProvider.Instance().UpdateFeed(FeedId, ModuleId, FeedName, FeedModuleId, FeedImportUrl, FeedUrl)
        End Sub

        Public Shared Sub DeleteFeed(ByVal FeedId As Integer)
            DataProvider.Instance().DeleteFeed(FeedId)
        End Sub

        Public Shared Function GetFeedRule(ByVal RuleId As Integer) As FeedRuleInfo
            Dim coll As New FeedRuleInfoCollection
            coll.Fill(DataProvider.Instance().GetFeedRule(RuleId))
            If coll.Count > 0 Then
                Return coll(0)
            Else
                Return Nothing
            End If
        End Function

        Public Shared Function GetFeedRules(ByVal FeedId As Integer) As FeedRuleInfoCollection
            Dim coll As New FeedRuleInfoCollection
            coll.Fill(DataProvider.Instance().GetFeedRules(FeedId))
            If coll.Count > 0 Then
                Return coll
            Else
                Return Nothing
            End If
        End Function

        Public Shared Function AddFeedRule(ByVal FeedId As Integer, ByVal RuleName As String, ByVal LookFor As String, ByVal ReplaceWith As String) As Integer
            Return DataProvider.Instance().AddFeedRule(FeedId, RuleName, LookFor, ReplaceWith)
        End Function

        Public Shared Sub UpdateFeedRule(ByVal RuleId As Integer, ByVal FeedId As Integer, ByVal RuleName As String, ByVal LookFor As String, ByVal ReplaceWith As String)
            DataProvider.Instance().UpdateFeedRule(RuleId, FeedId, RuleName, LookFor, ReplaceWith)
        End Sub

        Public Shared Sub DeleteFeedRule(ByVal RuleId As Integer)
            DataProvider.Instance().DeleteFeedRule(RuleId)
        End Sub

        Public Shared Function GetModuleIds(ByVal ModuleId As Integer) As ModuleIdInfo
            Dim coll As New ModuleIdInfoCollection
            coll.Fill(DataProvider.Instance().GetModuleIds(ModuleId))

            If Not coll Is Nothing Then
                If coll.Count > 0 Then
                    Return coll(0)
                Else
                    Return Nothing
                End If
            Else
                Return Nothing
            End If
        End Function

#End Region

        ''' <summary>
        ''' GetRSSEnabledModules - this method returns all non-Admin modules that have RSS enabled
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks>
        ''' If a host user is using the module, then all modules in the DNN instance are shown
        ''' </remarks>
        ''' <history>
        ''' </history>
        Public Shared Function GetRSSEnabledModules() As List(Of DotNetNuke.Entities.Modules.ModuleInfo)
            Dim user As New DotNetNuke.Entities.Users.UserInfo
            user = DotNetNuke.Entities.Users.UserController.GetCurrentUserInfo
            Dim stgs As New DotNetNuke.Entities.Portals.PortalSettings
            stgs = DotNetNuke.Entities.Portals.PortalController.GetCurrentPortalSettings

            Dim ctlMod As New DotNetNuke.Entities.Modules.ModuleController
            Dim collMod As New ArrayList
            collMod = ctlMod.GetAllModules

            Dim modInfo As New DnnModules.ModuleInfo
            Dim newColl As New List(Of DnnModules.ModuleInfo)

            For Each item As DnnModules.ModuleInfo In collMod
                modInfo = CType(item, DnnModules.ModuleInfo)
                If Not modInfo.IsAdmin Then
                    If user.IsSuperUser Then
                        ' gather all modules
                        If modInfo.DisplaySyndicate Then
                            newColl.Add(modInfo)
                        End If
                    Else
                        ' only gather modules for this portal
                        If modInfo.DisplaySyndicate AndAlso modInfo.PortalID = stgs.PortalId Then
                            newColl.Add(modInfo)
                        End If
                    End If
                End If
            Next

            newColl.Sort(New GenericComparer(Of Entities.Modules.ModuleInfo)("ModuleTitle", SortDirection.Ascending))

            Return newColl
        End Function

        ''' <summary>
        ''' GetPortalInfo - this method returns the portal information object for the portal
        ''' </summary>
        ''' <param name="PortalId"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Public Shared Function GetPortalInfo(ByVal PortalId As Integer) As Entities.Portals.PortalInfo
            Dim portals As New ArrayList
            Dim ctlPortal As New DotNetNuke.Entities.Portals.PortalController
            portals = ctlPortal.GetPortals

            For Each pItem As Entities.Portals.PortalInfo In portals
                If pItem.PortalID = PortalId Then
                    Return pItem
                End If
            Next

            Return Nothing
        End Function

        ''' <summary>
        ''' GetDNNRssUrl - this method returns the URL used to access the module RSS feed
        ''' </summary>
        ''' <param name="ModuleId"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Public Shared Function GetDNNRssUrl(ByVal ModuleId As Integer) As String
            Dim ctlModule As New DotNetNuke.Entities.Modules.ModuleController
            Dim miInfo As New ModuleIdInfo
            miInfo = FeedHandlerController.GetModuleIds(ModuleId)
            Dim mInfo As New DotNetNuke.Entities.Modules.ModuleInfo
            mInfo = ctlModule.GetModule(miInfo.ModuleId, miInfo.TabId, False)

            Return GetDNNRssUrl(mInfo)
        End Function

        ''' <summary>
        ''' GetDNNRssUrl - this method returns the URL used to access the module RSS feed
        ''' </summary>
        ''' <param name="mInfo"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Public Shared Function GetDNNRssUrl(ByVal mInfo As Entities.Modules.ModuleInfo) As String
            Dim ctlTab As New Entities.Tabs.TabController
            Dim tInfo As New Entities.Tabs.TabInfo
            tInfo = ctlTab.GetTab(mInfo.TabID, mInfo.TabID, False)

            Dim pInfo As New Entities.Portals.PortalInfo
            pInfo = FeedHandlerController.GetPortalInfo(mInfo.PortalID)

            Dim pAlias As New Entities.Portals.PortalAliasInfo
            Dim ctlAlias As New Entities.Portals.PortalAliasController
            pAlias = CType(ctlAlias.GetPortalAliasArrayByPortalID(mInfo.PortalID)(0), Entities.Portals.PortalAliasInfo)
            Dim stgs As New Entities.Portals.PortalSettings(mInfo.TabID, pAlias)

            'http://www.domain.com/Home/tabid/36/moduleid/349/RSS.aspx
            'http://www.domain.com/Home/tabid/36/portalid/0/moduleid/349/RSS.aspx
            Dim strLink As String = String.Concat("http://", stgs.PortalAlias.HTTPAlias, "/", _
                Regex.Replace(tInfo.TabName, "\W", ""), "/tabid/", mInfo.TabID, "/portalid/", mInfo.PortalID, "/moduleid/", _
                mInfo.ModuleID, "/RSS.aspx")

            Return strLink
        End Function

        ''' <summary>
        ''' GetFeedHandler - this method returns the URL used to access the feedhandler
        ''' </summary>
        ''' <param name="FeedId"></param>
        ''' <param name="ModuleId"></param>
        ''' <param name="FolderName"></param>
        ''' <param name="HttpAlias"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Public Overloads Shared Function GetFeedHandlerUrl(ByVal FeedId As Integer, ByVal ModuleId As Integer, ByVal FolderName As String, ByVal HttpAlias As String) As String
            Return GetFeedHandlerUrl(FeedId, ModuleId, FolderName, HttpAlias, Null.NullInteger)
        End Function

        ''' <summary>
        ''' GetFeedHandler - this method returns the URL used to access the feedhandler
        ''' </summary>
        ''' <param name="FeedId"></param>
        ''' <param name="ModuleId"></param>
        ''' <param name="FolderName"></param>
        ''' <param name="HttpAlias"></param>
        ''' <param name="ItemCount"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Public Overloads Shared Function GetFeedHandlerUrl(ByVal FeedId As Integer, ByVal ModuleId As Integer, ByVal FolderName As String, ByVal HttpAlias As String, ByVal ItemCount As Integer) As String
            If Not FeedId > Null.NullInteger Then
                Throw New ArgumentNullException("FeedId")
            End If
            If Not ModuleId > Null.NullInteger Then
                Throw New ArgumentNullException("ModuleId")
            End If
            If String.IsNullOrEmpty(FolderName) Then
                Throw New ArgumentNullException("FolderName")
            End If
            If String.IsNullOrEmpty(HttpAlias) Then
                Throw New ArgumentNullException("HttpAlias")
            End If
            If Not ItemCount > Null.NullInteger Then
                ItemCount = 10
            End If

            ' was going to use token replace, but that's just overkill for this
            'Dim tr As New DotNetNuke.Services.Tokens.TokenReplace
            'tr.DebugMessages = False
            'tr.ModuleId = ModuleId
            'tr.ModuleInfo = infoModule
            'tr.PortalSettings = settingsPortal
            'tr.ReplaceEnvironmentTokens(FEEDHANDLER_URL)

            Dim strUrl As String = String.Format(FEEDHANDLER_URL, HttpAlias, FolderName, FeedId, ModuleId, ItemCount)
            Return strUrl
        End Function

        ''' <summary>
        ''' ApplyFeedRule - this method applies a single rule to the XML feed
        ''' </summary>
        ''' <param name="XmlFeed"></param>
        ''' <param name="LookFor"></param>
        ''' <param name="ReplaceWith"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Public Shared Function ApplyFeedRule(ByVal XmlFeed As String, ByVal LookFor As String, ByVal ReplaceWith As String) As String
            Return Regex.Replace(XmlFeed, LookFor, ReplaceWith)
        End Function

        ''' <summary>
        ''' ApplyFeedRules - this method applies a collection of rules to the XML feed
        ''' </summary>
        ''' <param name="XmlFeed"></param>
        ''' <param name="FeedRules"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Public Shared Function ApplyFeedRules(ByVal XmlFeed As String, ByVal FeedRules As FeedRuleInfoCollection) As String
            For Each rule As FeedRuleInfo In FeedRules
                XmlFeed = ApplyFeedRule(XmlFeed, rule.LookFor, rule.ReplaceWith)
            Next

            Return XmlFeed
        End Function

        ''' <summary>
        ''' ImportXmlFeed - this method imports the DNN module RSS feed into a string object
        ''' </summary>
        ''' <param name="ModuleId"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Public Overloads Shared Function ImportXmlFeed(ByVal ModuleId As Integer) As String
            Dim strRequestUrl As String = FeedHandlerController.GetDNNRssUrl(ModuleId)
            Return ImportXmlFeed(strRequestUrl)
        End Function

        ''' <summary>
        ''' ImportXmlFeed - this method imports the DNN module RSS feed into a string object
        ''' </summary>
        ''' <param name="FeedUrl"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        ''' <history>
        ''' </history>
        Public Overloads Shared Function ImportXmlFeed(ByVal FeedUrl As String) As String
            Dim strReturn As String = String.Empty
            Dim httpResponse As HttpWebResponse = Nothing

            Try
                Dim UseSSLConnection As Boolean = False
                Dim objBytes As Byte() = Encoding.UTF8.GetBytes("DotNetNuke Rules!")
                Dim httpRequest As HttpWebRequest = CType(WebRequest.Create(FeedUrl), HttpWebRequest)

                httpRequest.Method = "Post"
                httpRequest.ContentLength = objBytes.Length
                httpRequest.ContentType = "text/html"
                ' *** http://msdn.microsoft.com/en-us/library/kd3cf2ex.aspx
                ' *** Despite the fact that no proxy is configured on the machine, and IE/WinINet
                ' *** are configured to never use a proxy, with automatic detection disabled,
                ' *** HttpWebRequest was apparently trying to detect a proxy. Set req.Proxy = null
                ' *** to get the 1.1 behavior (do not attempt to detect proxy).
                httpRequest.Proxy = Nothing

                If Not httpRequest Is Nothing Then

                    Dim requestStream As Stream = httpRequest.GetRequestStream()

                    ' *** Possible if a WebException is thrown before...
                    If Not requestStream Is Nothing Then

                        Using (requestStream)
                            requestStream.Write(objBytes, 0, objBytes.Length)
                        End Using

                        ' *** The WebException with catch this below...
                        httpResponse = CType(httpRequest.GetResponse(), HttpWebResponse)

                        ' *** Possible if a WebException is thrown before...
                        If Not httpResponse Is Nothing Then

                            If Not httpResponse.StatusCode = HttpStatusCode.OK Then
                                Throw New ApplicationException(String.Format("POST failed. Received HTTP {0}", httpResponse.StatusCode))
                            Else
                                Using receiveStream As Stream = httpResponse.GetResponseStream()
                                    Using readStream As New StreamReader(receiveStream, System.Text.Encoding.GetEncoding(CONTENT_ENCODING))
                                        strReturn = readStream.ReadToEnd
                                    End Using
                                End Using
                            End If

                            httpResponse.Close()

                        End If
                    End If
                End If
            Finally
                If Not (httpResponse Is Nothing) Then
                    httpResponse.Close()
                End If
            End Try

            Return strReturn
        End Function

    End Class

End Namespace